import os
import sys
import uuid
import json
import importlib.util
import time
import hashlib
import traceback
from functools import wraps
import threading

from flask import Flask, request, jsonify, render_template, redirect, url_for, abort, g, session
from werkzeug.exceptions import BadRequest, NotFound, Unauthorized
from authlib.jose import jwt
from authlib.jose.errors import JoseError
from pymysql.cursors import DictCursor

import logging
from logging.handlers import RotatingFileHandler
# 导入数据库连接池
from db_pool import get_db_connection
from config import Config
from script_storage import script_storage
from metadata_storage import metadata_storage
import re
import subprocess
import shutil

# 添加这个导入
from consistency_check import check_data_consistency, cleanup_orphaned_scripts


# 创建 logger
logger = logging.getLogger('my_app')
logger.setLevel(logging.DEBUG)
# 创建格式化器
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# 创建文件处理器（支持日志轮转）
file_handler = RotatingFileHandler(
    'logs/app.log',
    maxBytes=10 * 1024 * 1024,  # 10MB
    backupCount=5
)
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
# 创建控制台处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(formatter)
# 添加处理器到 logger
logger.addHandler(file_handler)
logger.addHandler(console_handler)

# 添加持久化包目录到 Python 路径
PERSISTENT_PACKAGE_DIR = "/opt/install_packages"
if PERSISTENT_PACKAGE_DIR not in sys.path:
    sys.path.insert(0, PERSISTENT_PACKAGE_DIR)

# 存储安装任务状态
installation_tasks = {}
uninstallation_tasks = {}
tasks_lock = threading.Lock()

# 创建应用
app = Flask(__name__)
app.config.from_object(Config)

# 确保API目录存在
os.makedirs(Config.API_DIR, exist_ok=True)

# # 鉴权Token接口
# @app.route('/api/auth_token', methods=['POST'])
# def auth_token():
#     try:
#         data = request.get_json()
#         if not data:
#             return jsonify({'error': 'Invalid request data'}), 400
#
#         # 生成Token逻辑（需验证用户凭据）
#         if data.get('action') == 'generate':
#             username = data.get('username')
#             password = data.get('password')
#             if not username or not password:
#                 return jsonify({'error': 'Username and password required'}), 400
#
#             # 连接数据库验证用户
#             try:
#                 db = get_db_connection()
#                 cursor = db.cursor()
#                 cursor.execute("SELECT password_hash, salt FROM users WHERE username = %s", (username,))
#                 user = cursor.fetchone()
#                 db.close()
#
#                 if not user:
#                     return jsonify({'error': 'Invalid username or password'}), 401
#
#                 # 验证密码哈希（加盐）
#                 input_hash = hashlib.sha256((password + user['salt']).encode()).hexdigest()
#                 if input_hash != user['password_hash']:
#                     return jsonify({'error': 'Invalid username or password'}), 401
#
#                 # 生成Token
#                 token = str(uuid.uuid4())
#                 return jsonify({'token': token}), 200
#             except Exception as e:
#                 logger.error(f'执行过程中发生错误: {e}', exc_info=True)
#                 return jsonify({'error': f'Database error: {str(e)}'}), 500
#
#         # 验证Token逻辑
#         elif data.get('action') == 'validate':
#             # 这里可以添加验证逻辑
#             return jsonify({'valid': True}), 200
#
#         else:
#             return jsonify({'error': 'Invalid action'}), 400
#     except Exception as e:
#         logger.error(f"异常：{e}")
#         return jsonify({'error': str(e)}), 500

# 存储API元数据和模块缓存
api_metadata = {}
module_cache = {}
last_modified_cache = {}


def load_api_metadata():
    """加载API元数据 - 修复版本"""
    global api_metadata

    # 先检查数据一致性
    logger.info("Loading API metadata with consistency check...")
    success, message = check_data_consistency()
    if not success:
        logger.error(f"Consistency check failed: {message}")

    # 使用元数据存储抽象层
    new_metadata, error = metadata_storage.load_metadata()
    if error:
        logger.error(f'ERROR: Failed to load API metadata: {error}')
        # 如果加载失败，保持现有元数据不变
        if not api_metadata:
            api_metadata = {}
    else:
        api_metadata = new_metadata
        logger.info(f'DEBUG: Loaded {len(api_metadata)} APIs successfully')

    # 验证每个API的脚本是否存在
    valid_apis = {}
    for api_id, api_info in api_metadata.items():
        if script_storage.script_exists(api_id):
            valid_apis[api_id] = api_info
        else:
            logger.warning(f"Removing invalid API {api_id}: script not found")

    if len(valid_apis) != len(api_metadata):
        logger.warning(f"Removed {len(api_metadata) - len(valid_apis)} invalid APIs")
        api_metadata = valid_apis
        # 保存修复后的元数据
        save_api_metadata()

    return api_metadata


def save_api_metadata():
    """保存API元数据"""
    # 使用元数据存储抽象层
    success, error = metadata_storage.save_metadata(api_metadata)
    if not success:
        print(f'ERROR 保存API元数据失败: {error}')
    return success, error  # 添加这行返回语句

def log_access(api_id, function_name, status, message, execution_time):
    """记录API访问日志"""
    log_entry = {
        'timestamp': time.strftime("%Y-%m-%d %H:%M:%S"),
        'api_id': api_id,
        'function': function_name,
        'status': status,
        'message': message,
        'execution_time': execution_time,
        'ip': request.remote_addr,
        'user_agent': request.headers.get('User-Agent', ''),
        'method': request.method
    }

    with open(Config.LOG_FILE, 'a') as f:
        f.write(json.dumps(log_entry) + '\n')


def hash_password(password):
    """使用SHA256哈希密码"""
    return hashlib.sha256(password.encode('utf-8')).hexdigest()


def require_jwt(view_func):
    """JWT鉴权装饰器"""

    @wraps(view_func)
    def decorated_function(*args, **kwargs):
        # 检查API是否需要鉴权
        api_id = kwargs.get('api_id')

        # 如果API ID未提供（如自定义路径），尝试查找API ID
        if api_id is None:
            custom_path = kwargs.get('custom_path', '')
            if custom_path:
                for aid, api_info in api_metadata.items():
                    for fname, func_details in api_info.get('functions', {}).items():
                        if func_details.get('custom_path') == f'/{custom_path}':
                            api_id = aid
                            break
        if api_id is None:
            return redirect(url_for('login'))

        # 如果API ID存在且需要鉴权
        if api_id and api_metadata.get(api_id, {}).get('auth_required', True):
            # 从请求头获取JWT token
            auth_header = request.headers.get('Authorization', '')
            if not auth_header.startswith('Bearer '):
                abort(401, description="Invalid or missing token")

            token = auth_header[7:]
            try:
                # 验证token - 使用正确的方法
                claims = jwt.decode(token, Config.JWT_SECRET)
                # 验证过期时间
                if 'exp' in claims and claims['exp'] < time.time():
                    abort(401, description="Token has expired")
                g.user = claims.get('sub')
            except JoseError as e:
                abort(401, description=f"Invalid token: {str(e)}")
        elif not api_id or not api_metadata.get(api_id, {}).get('auth_required', False):
            # 不需要鉴权的API直接放行
            return view_func(*args, **kwargs)

        return view_func(*args, **kwargs)

    return decorated_function


# 添加JWT token生成接口
@app.route(f'{Config.API_PREFIX}/auth/token', methods=['POST'])
def generate_token():
    """生成JWT token接口"""
    data = request.get_json()
    username = data.get('username')
    password = data.get('password')

    if not username or not password:
        return jsonify({'error': 'Username and password are required'}), 400

    try:
        # 连接MySQL验证用户
        connection = get_db_connection()
        cursor = connection.cursor(DictCursor)

        cursor.execute("SELECT password_hash, salt FROM users WHERE username = %s", (username,))
        user = cursor.fetchone()

        if not user:
            connection.close()
            return jsonify({'error': 'Invalid username or password'}), 401

        # 验证密码哈希（加盐）
        input_hash = hashlib.sha256((password + user['salt']).encode()).hexdigest()
        if input_hash != user['password_hash']:
            connection.close()
            return jsonify({'error': 'Invalid username or password'}), 401

        # 生成JWT token
        header = {'alg': Config.JWT_ALGORITHM}
        payload = {
            'sub': username,
            'exp': int(time.time()) + Config.JWT_EXPIRE
        }
        token = jwt.encode(header, payload, Config.JWT_SECRET)
        connection.close()

        return jsonify({
            'access_token': token.decode('utf-8'),
            'token_type': 'Bearer',
            'expires_in': Config.JWT_EXPIRE
        })

    except Exception as e:
        return jsonify({'error': f'Database error: {str(e)}'}), 500


def load_api_module(api_id):
    """加载API模块，使用缓存机制"""
    # 检查脚本是否存在 - 修改为使用存储抽象层
    if not script_storage.script_exists(api_id):
        error_msg = f"Script not found for API: {api_id}"
        print(f"ERROR: {error_msg}")
        return None, error_msg

    # 获取脚本最后修改时间
    if Config.SCRIPT_STORAGE == 'file':
        script_path = os.path.join(Config.API_DIR, f'{api_id}.py')
        last_modified = os.path.getmtime(script_path)
    else:
        # 对于数据库存储，尝试获取实际的更新时间
        try:
            connection = get_db_connection()
            cursor = connection.cursor()
            cursor.execute(
                f"SELECT UNIX_TIMESTAMP(updated_at) FROM {Config.SCRIPTS_TABLE} WHERE api_id = %s",
                (api_id,)
            )
            result = cursor.fetchone()
            connection.close()
            last_modified = result[0] if result else time.time()
        except Exception as e:
            print(f"WARNING: Failed to get script update time: {str(e)}")
            last_modified = time.time()

    # 检查缓存是否有效
    if api_id in module_cache and last_modified == last_modified_cache.get(api_id):
        print(f"DEBUG: Using cached module for API {api_id}")
        return module_cache[api_id], None

    try:
        # 加载脚本内容 - 修改为使用存储抽象层
        print(f"DEBUG: Loading script content for API {api_id}")
        script_content, error = script_storage.load_script(api_id)
        if error:
            error_msg = f"Failed to load script content: {error}"
            print(f"ERROR: {error_msg}")
            return None, error_msg

        # 确保脚本内容不为空
        if not script_content or script_content.strip() == '':
            error_msg = f"Script content is empty for API: {api_id}"
            print(f"ERROR: {error_msg}")
            return None, error_msg

        # 创建临时文件用于模块加载
        temp_dir = os.path.join(os.path.dirname(__file__), 'temp_scripts')
        os.makedirs(temp_dir, exist_ok=True)
        temp_script_path = os.path.join(temp_dir, f'{api_id}.py')

        with open(temp_script_path, 'w', encoding='utf-8') as f:
            f.write(script_content)

        # 先验证语法
        try:
            with open(temp_script_path, 'r', encoding='utf-8') as f:
                compile(f.read(), temp_script_path, 'exec')
        except SyntaxError as e:
            error_msg = f"Script syntax error: {str(e)}"
            print(f"ERROR: {error_msg}")
            # 清理临时文件
            try:
                os.remove(temp_script_path)
            except:
                pass
            return None, error_msg

        # 加载模块
        spec = importlib.util.spec_from_file_location(f"api_{api_id}", temp_script_path)
        if spec is None:
            error_msg = "Failed to create module spec"
            print(f"ERROR: {error_msg}")
            # 清理临时文件
            try:
                os.remove(temp_script_path)
            except:
                pass
            return None, error_msg

        module = importlib.util.module_from_spec(spec)
        try:
            spec.loader.exec_module(module)
        except Exception as e:
            error_msg = f"Error executing module {api_id}: {str(e)}"
            print(f"ERROR: {error_msg}")
            # 清理临时文件
            try:
                os.remove(temp_script_path)
            except:
                pass
            return None, error_msg

        # 更新缓存
        module_cache[api_id] = module
        last_modified_cache[api_id] = last_modified

        # 清理临时文件
        try:
            os.remove(temp_script_path)
        except:
            pass

        print(f"DEBUG: Module loaded successfully for API {api_id}")
        return module, None
    except Exception as e:
        error_msg = f"Error loading module {api_id}: {str(e)}\n{traceback.format_exc()}"
        print(f"ERROR: {error_msg}")
        # 清理临时文件
        try:
            os.remove(temp_script_path)
        except:
            pass
        return None, error_msg


def get_api_endpoint(api_id, function_name, custom_path=None):
    """获取完整的API端点路径"""
    if custom_path:
        # 确保路径以斜杠开头
        return custom_path if custom_path.startswith('/') else f'/{custom_path}'
    return f"{Config.API_PREFIX}/{api_id}/{function_name}"


## 用于卸载包之后
def clear_package_cache(package_name):
    """清除特定包的模块缓存"""
    # 获取所有已加载的模块
    modules_to_clear = []
    for module_name in list(sys.modules.keys()):
        # 检查模块是否属于要卸载的包
        if (module_name == package_name or
                module_name.startswith(package_name + '.')):
            modules_to_clear.append(module_name)

    # 清除这些模块
    for module_name in modules_to_clear:
        del sys.modules[module_name]

    # 清除 importlib 的缓存
    importlib.invalidate_caches()

    return len(modules_to_clear)


@app.route(f'{Config.API_PREFIX}/<path:custom_path>', methods=['POST'])
@require_jwt
def execute_custom_api_function(custom_path):
    """执行自定义路径的API函数"""
    # 查找匹配的API和函数
    full_path = f'/{custom_path}'
    for api_id, api_info in api_metadata.items():
        for func_name, func_details in api_info.get('functions', {}).items():
            if func_details.get('custom_path') == full_path:
                return execute_api_function_impl(api_id, func_name)

    abort(404, description=f"No API function found for path '{full_path}'")


def execute_api_function_impl(api_id, function_name):
    """执行API函数的实现"""
    # 检查API是否存在
    if api_id not in api_metadata:
        log_access(api_id, function_name, 'error', f"API '{api_id}' not found", 0)
        abort(404, description=f"API '{api_id}' not found")

    # 加载模块
    module, error = load_api_module(api_id)
    if module is None:
        log_access(api_id, function_name, 'error', f"Failed to load API module '{api_id}': {error}", 0)
        abort(500, description=f"Failed to load API module '{api_id}': {error}")

    # 获取函数
    func = getattr(module, function_name, None)
    if not func or not callable(func):
        log_access(api_id, function_name, 'error', f"Function '{function_name}' not found", 0)
        abort(404, description=f"Function '{function_name}' not found in API '{api_id}'")

    # 解析请求数据
    try:
        data = request.get_json(force=True) or {}
    except BadRequest:
        data = {}

    # 执行函数
    try:
        start_time = time.perf_counter()
        result = func(**data)
        execution_time = time.perf_counter() - start_time

        # 记录成功访问
        log_access(api_id, function_name, 'success', '', execution_time)

        response_data = {
            'status': 'success',
            'result': result,
            'api_id': api_id,
            'function': function_name,
            'execution_time': f"{execution_time:.4f}s",
        }

        # 如果启用了鉴权，添加执行用户信息
        if hasattr(g, 'user'):
            response_data['executed_by'] = g.user

        return jsonify(response_data)
    except Exception as e:
        # 记录错误访问
        log_access(api_id, function_name, 'error', str(e), 0)
        return jsonify({
            'status': 'error',
            'message': str(e),
            'api_id': api_id,
            'function': function_name
        }), 500


@app.route(f'{Config.API_PREFIX}/<api_id>/<function_name>', methods=['POST'])
@require_jwt
def execute_api_function(api_id, function_name):
    """执行API函数（标准路径）"""
    return execute_api_function_impl(api_id, function_name)


@app.route('/')
def index():
    """首页 - 需要认证的API列表"""
    if 'user' not in session:
        return redirect(url_for('login'))

    # 计算函数总数
    total_functions = 0
    for api in api_metadata.values():
        total_functions += len(api.get('functions', {}))

    return render_template('index.html',
                           apis=api_metadata,
                           total_functions=total_functions)


@app.route('/logout')
def logout():
    """退出登录"""
    session.pop('user', None)
    return redirect(url_for('login'))


@app.route('/login', methods=['GET', 'POST'])
def login():
    """登录页面"""
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')

        # 连接数据库验证用户

        try:
            db = get_db_connection()
            cursor = db.cursor(DictCursor)
            cursor.execute("SELECT password_hash, salt FROM users WHERE username = %s", (username,))
            user = cursor.fetchone()
            db.close()

            if not user:
                return render_template('login.html', error="Invalid username or password")

            # 验证密码哈希（加盐）
            input_hash = hashlib.sha256((password + user['salt']).encode()).hexdigest()
            if input_hash != user['password_hash']:
                return render_template('login.html', error="Invalid username or password")

            # 生成JWT token
            header = {'alg': Config.JWT_ALGORITHM}
            payload = {
                'sub': username,
                'exp': int(time.time()) + Config.JWT_EXPIRE
            }
            token = jwt.encode(header, payload, Config.JWT_SECRET)

            # 存储token在session中
            session['user'] = username
            session['token'] = token.decode('utf-8')
            return redirect(url_for('index'))
        except Exception as e:

            return render_template('login.html', error=f"Database error: {str(e)}")
    return render_template('login.html')


@app.route('/create', methods=['GET', 'POST'])
def create_api():
    """创建新API - 完整修复版本"""
    if request.method == 'POST':
        api_id = None  # 提前定义以便错误处理
        try:
            # 获取表单数据
            api_name = request.form.get('api_name', 'Untitled API').strip()
            description = request.form.get('description', '').strip()
            script_code = request.form.get('script', '')
            custom_prefix = request.form.get('custom_prefix', Config.API_PREFIX).strip()
            auth_required = request.form.get('auth_required', 'off') == 'on'

            # 验证输入
            if not api_name:
                return render_template('create_edit.html', mode='create',
                                       error="API name is required",
                                       api_name=api_name,
                                       description=description,
                                       custom_prefix=custom_prefix,
                                       script_content=script_code,
                                       auth_required=auth_required)

            if not script_code or script_code.strip() == '':
                return render_template('create_edit.html', mode='create',
                                       error="Script content is required",
                                       api_name=api_name,
                                       description=description,
                                       custom_prefix=custom_prefix,
                                       script_content=script_code,
                                       auth_required=auth_required)

            # 生成唯一API ID
            api_id = str(uuid.uuid4())[:8]
            logger.info(f"Creating API {api_id} with name '{api_name}'")

            # 先验证脚本语法
            logger.info(f"Validating script syntax for API {api_id}")
            try:
                # 创建临时文件验证语法
                temp_dir = os.path.join(os.path.dirname(__file__), 'temp_scripts')
                os.makedirs(temp_dir, exist_ok=True)
                temp_script_path = os.path.join(temp_dir, f'{api_id}_validate.py')

                with open(temp_script_path, 'w', encoding='utf-8') as f:
                    f.write(script_code)

                # 尝试编译来验证语法
                with open(temp_script_path, 'r', encoding='utf-8') as f:
                    compile(f.read(), temp_script_path, 'exec')

                # 清理临时文件
                try:
                    os.remove(temp_script_path)
                except:
                    pass

            except SyntaxError as e:
                error_msg = f"Script syntax error: {str(e)}"
                logger.error(f"ERROR: {error_msg}")
                # 清理临时文件
                try:
                    os.remove(temp_script_path)
                except:
                    pass
                return render_template('create_edit.html', mode='create',
                                       error=error_msg,
                                       api_name=api_name,
                                       description=description,
                                       custom_prefix=custom_prefix,
                                       script_content=script_code,
                                       auth_required=auth_required)
            except Exception as e:
                error_msg = f"Script validation error: {str(e)}"
                logger.error(f"ERROR: {error_msg}")
                # 清理临时文件
                try:
                    os.remove(temp_script_path)
                except:
                    pass
                return render_template('create_edit.html', mode='create',
                                       error=error_msg,
                                       api_name=api_name,
                                       description=description,
                                       custom_prefix=custom_prefix,
                                       script_content=script_code,
                                       auth_required=auth_required)

            # 先保存脚本
            logger.info(f"Saving script for API {api_id}")
            success, error = script_storage.save_script(api_id, script_code)
            if not success:
                error_msg = f"Failed to save script: {error}"
                logger.error(error_msg)
                return render_template('create_edit.html', mode='create',
                                       error=error_msg,
                                       api_name=api_name,
                                       description=description,
                                       custom_prefix=custom_prefix,
                                       script_content=script_code,
                                       auth_required=auth_required)

            # 验证脚本是否真的保存成功
            saved_content, error = script_storage.load_script(api_id)
            if error or not saved_content:
                error_msg = f"Failed to verify script save: {error or 'Empty content'}"
                logger.error(error_msg)
                # 删除可能已保存的脚本
                script_storage.delete_script(api_id)
                return render_template('create_edit.html', mode='create',
                                       error=error_msg,
                                       api_name=api_name,
                                       description=description,
                                       custom_prefix=custom_prefix,
                                       script_content=script_code,
                                       auth_required=auth_required)

            # 现在保存元数据
            api_metadata[api_id] = {
                'name': api_name,
                'description': description,
                'created_at': time.strftime("%Y-%m-%d %H:%M:%S"),
                'custom_prefix': custom_prefix,
                'auth_required': auth_required,
                'api_key': str(uuid.uuid4()),
                'functions': {}
            }

            # 保存元数据
            logger.info(f"Saving metadata for API {api_id}")
            success, error = save_api_metadata()  # 现在这个函数会返回 (success, error)
            if not success:
                error_msg = f"Failed to save metadata: {error}"
                logger.error(error_msg)
                # 回滚：删除脚本和内存中的元数据
                script_storage.delete_script(api_id)
                if api_id in api_metadata:
                    del api_metadata[api_id]
                return render_template('create_edit.html', mode='create',
                                       error=error_msg,
                                       api_name=api_name,
                                       description=description,
                                       custom_prefix=custom_prefix,
                                       script_content=script_code,
                                       auth_required=auth_required)

            # 尝试加载函数信息（可选，不影响API创建）
            logger.info(f"Attempting to load module for API {api_id}")
            module, error = load_api_module(api_id)
            if module:
                logger.info(f"Module loaded successfully, extracting functions")
                functions = [func for func in dir(module)
                             if callable(getattr(module, func)) and not func.startswith('_')]

                for func_name in functions:
                    func = getattr(module, func_name)

                    # 获取自定义路径（如果有）
                    custom_path_key = f"path_{func_name}"
                    custom_path = request.form.get(custom_path_key, '').strip()

                    # 构建默认路径
                    default_path = f"{Config.API_PREFIX}/{api_id}/{func_name}"

                    api_metadata[api_id]['functions'][func_name] = {
                        'endpoint': get_api_endpoint(api_id, func_name, custom_path),
                        'custom_path': f"/{custom_path}" if custom_path else None,
                        'description': func.__doc__ or '',
                        'default_path': default_path
                    }

                logger.info(f"Found {len(functions)} functions in script")

                # 如果有函数信息，再次保存元数据
                success, error = save_api_metadata()
                if not success:
                    logger.warning(f"Failed to save metadata with function information: {error}")
                    # 不阻止重定向，只是记录警告
            else:
                # 处理脚本错误 - 但仍然保存API，只是记录错误
                error_msg = f"Failed to load API module '{api_id}': {error}"
                logger.warning(f"WARNING: {error_msg}")
                api_metadata[api_id]['load_error'] = error_msg
                # 设置空的函数列表
                api_metadata[api_id]['functions'] = {}

            logger.info(f"API {api_id} created successfully, redirecting to detail page")
            return redirect(url_for('api_detail', api_id=api_id))

        except Exception as e:
            error_msg = f"Unexpected error during API creation: {str(e)}"
            logger.error(error_msg)
            logger.error(traceback.format_exc())

            # 确保清理：如果已经生成了api_id，删除可能已保存的数据
            if api_id:
                try:
                    script_storage.delete_script(api_id)
                except Exception as delete_error:
                    logger.error(f"Failed to cleanup script: {delete_error}")

                if api_id in api_metadata:
                    del api_metadata[api_id]
                    # 尝试保存清理后的元数据
                    try:
                        save_api_metadata()
                    except:
                        pass

            return render_template('create_edit.html', mode='create',
                                   error=error_msg,
                                   api_name=api_name if 'api_name' in locals() else '',
                                   description=description if 'description' in locals() else '',
                                   custom_prefix=custom_prefix if 'custom_prefix' in locals() else Config.API_PREFIX,
                                   script_content=script_code if 'script_code' in locals() else '',
                                   auth_required=auth_required if 'auth_required' in locals() else False)

    # GET请求 - 显示创建表单
    return render_template('create_edit.html', mode='create', custom_prefix=Config.API_PREFIX)

@app.route('/api/<api_id>')
def api_detail(api_id):
    """API详情页面"""
    if api_id not in api_metadata:
        abort(404, description=f"API '{api_id}' not found")

    api_info = api_metadata[api_id]
    api_info['id'] = api_id

    # 添加调试信息
    logging.debug(f"DEBUG: Loading script for API {api_id}")
    logging.debug(f"DEBUG: Storage type: {Config.SCRIPT_STORAGE}")

    # 读取脚本内容 - 修改为使用存储抽象层
    script_content, error = script_storage.load_script(api_id)
    if error:
        # 添加更详细的错误信息
        logging.debug(f"ERROR: Failed to load script for API {api_id}: {error}")
        script_content = f"# Error loading script: {error}"

        # 如果脚本加载失败，确保函数列表为空
        if 'functions' not in api_info:
            api_info['functions'] = {}

    return render_template('api_detail.html', api=api_info, script_content=script_content,
                           api_prefix=api_info.get('custom_prefix', Config.API_PREFIX))

@app.route('/get_token')
def get_token():
    """获取 Token 页面"""
    return render_template('get_token.html')


@app.route('/api/<api_id>/edit', methods=['GET', 'POST'])
def edit_api(api_id):
    """编辑API"""
    if api_id not in api_metadata:
        abort(404, description=f"API '{api_id}' not found")

    api_info = api_metadata[api_id]

    if request.method == 'POST':
        # 获取表单数据
        api_name = request.form.get('api_name', api_info['name']).strip()
        description = request.form.get('description', api_info.get('description', '')).strip()
        script_code = request.form.get('script', '')
        custom_prefix = request.form.get('custom_prefix', api_info.get('custom_prefix', Config.API_PREFIX)).strip()
        auth_required = request.form.get('auth_required', 'off') == 'on'

        # 验证输入
        if not api_name:
            return render_template('create_edit.html', mode='edit',
                                   error="API name is required",
                                   api_id=api_id,
                                   api_name=api_name,
                                   description=description,
                                   custom_prefix=custom_prefix,
                                   script_content=script_code,
                                   auth_required=auth_required)

        # 先验证脚本语法
        try:
            temp_dir = os.path.join(os.path.dirname(__file__), 'temp_scripts')
            os.makedirs(temp_dir, exist_ok=True)
            temp_script_path = os.path.join(temp_dir, f'{api_id}_validate_edit.py')

            with open(temp_script_path, 'w', encoding='utf-8') as f:
                f.write(script_code)

            # 尝试编译来验证语法
            with open(temp_script_path, 'r', encoding='utf-8') as f:
                compile(f.read(), temp_script_path, 'exec')

            # 清理临时文件
            try:
                os.remove(temp_script_path)
            except:
                pass

        except SyntaxError as e:
            error_msg = f"Script syntax error: {str(e)}"
            print(f"ERROR: {error_msg}")
            # 清理临时文件
            try:
                os.remove(temp_script_path)
            except:
                pass
            return render_template('create_edit.html', mode='edit',
                                   error=error_msg,
                                   api_id=api_id,
                                   api_name=api_name,
                                   description=description,
                                   custom_prefix=custom_prefix,
                                   script_content=script_code,
                                   auth_required=auth_required)
        except Exception as e:
            error_msg = f"Script validation error: {str(e)}"
            print(f"ERROR: {error_msg}")
            # 清理临时文件
            try:
                os.remove(temp_script_path)
            except:
                pass
            return render_template('create_edit.html', mode='edit',
                                   error=error_msg,
                                   api_id=api_id,
                                   api_name=api_name,
                                   description=description,
                                   custom_prefix=custom_prefix,
                                   script_content=script_code,
                                   auth_required=auth_required)

        # 保存脚本文件
        success, error = script_storage.save_script(api_id, script_code)
        if not success:
            return render_template('create_edit.html', mode='edit',
                                   error=f"Failed to save script: {error}",
                                   api_id=api_id,
                                   api_name=api_name,
                                   description=description,
                                   custom_prefix=custom_prefix,
                                   script_content=script_code,
                                   auth_required=auth_required)

        # 清除缓存
        if api_id in module_cache:
            del module_cache[api_id]
        if api_id in last_modified_cache:
            del last_modified_cache[api_id]

        # 重新加载函数信息
        api_info['name'] = api_name
        api_info['description'] = description
        api_info['custom_prefix'] = custom_prefix
        api_info['auth_required'] = auth_required
        api_info['updated_at'] = time.strftime("%Y-%m-%d %H:%M:%S")
        api_info['functions'] = {}

        # 清除之前的加载错误
        if 'load_error' in api_info:
            del api_info['load_error']

        module, error = load_api_module(api_id)
        if module:
            functions = [func for func in dir(module)
                         if callable(getattr(module, func)) and not func.startswith('_')]

            for func_name in functions:
                func = getattr(module, func_name)

                # 获取自定义路径（如果有）
                custom_path_key = f"path_{func_name}"
                custom_path = request.form.get(custom_path_key, '').strip()

                # 如果表单中没有提供自定义路径，尝试使用之前的设置
                if not custom_path and 'functions' in api_info:
                    old_func = api_info['functions'].get(func_name, {})
                    custom_path = old_func.get('custom_path', '')
                    # 去掉开头的斜杠（如果有）
                    if custom_path and custom_path.startswith('/'):
                        custom_path = custom_path[1:]

                # 构建默认路径
                default_path = f"{Config.API_PREFIX}/{api_id}/{func_name}"

                api_info['functions'][func_name] = {
                    'endpoint': get_api_endpoint(api_id, func_name, custom_path),
                    'custom_path': f"/{custom_path}" if custom_path else None,
                    'description': func.__doc__ or '',
                    'default_path': default_path
                }
        else:
            # 处理脚本错误
            api_info['load_error'] = error
            # 确保函数列表为空
            api_info['functions'] = {}

        success, error = save_api_metadata()  # 修复这里
        if not success:
            logger.error(f"Failed to save metadata during edit: {error}")

        return redirect(url_for('api_detail', api_id=api_id))

    # 读取脚本内容
    script_content, error = script_storage.load_script(api_id)
    if error:
        script_content = f"# Error loading script: {error}"

    return render_template('create_edit.html', mode='edit',
                           api_id=api_id,
                           api_name=api_info['name'],
                           description=api_info.get('description', ''),
                           custom_prefix=api_info.get('custom_prefix', Config.API_PREFIX),
                           script_content=script_content,
                           api=api_info,
                           auth_required=api_info.get('auth_required', True))


@app.route('/api/<api_id>/delete', methods=['POST'])
def delete_api(api_id):
    """删除API"""
    if api_id not in api_metadata:
        abort(404, description=f"API '{api_id}' not found")

    # 删除脚本文件
    success, error = script_storage.delete_script(api_id)
    if not success:
        # 记录错误但继续执行其他删除操作
        logger.error(f"Failed to delete script for API {api_id}: {error}")

    # 清除缓存
    if api_id in module_cache:
        del module_cache[api_id]
    if api_id in last_modified_cache:
        del last_modified_cache[api_id]

    # 从元数据中移除
    del api_metadata[api_id]
    success, error = save_api_metadata()  # 修复这里
    if not success:
        logger.error(f"Failed to save metadata after deletion: {error}")

    return redirect(url_for('index'))


@app.route('/api/<api_id>/regenerate_key', methods=['POST'])
def regenerate_api_key(api_id):
    """重新生成API密钥"""
    if api_id not in api_metadata:
        abort(404, description=f"API '{api_id}' not found")

    # 生成新的API密钥
    api_metadata[api_id]['api_key'] = str(uuid.uuid4())
    save_api_metadata()

    return redirect(url_for('api_detail', api_id=api_id))


@app.route('/api/<api_id>/toggle_auth', methods=['POST'])
def toggle_auth(api_id):
    """切换鉴权设置"""
    if api_id not in api_metadata:
        abort(404, description=f"API '{api_id}' not found")

    # 切换鉴权设置
    api_metadata[api_id]['auth_required'] = not api_metadata[api_id].get('auth_required', True)
    save_api_metadata()

    return redirect(url_for('api_detail', api_id=api_id))


# 设置用户
def get_all_users():
    """从数据库获取所有用户"""
    try:
        db = get_db_connection()
        cursor = db.cursor(DictCursor)
        cursor.execute("SELECT username FROM users")
        users = [row['username'] for row in cursor.fetchall()]
        db.close()
        return users
    except Exception as e:
        logger.error(f"获取用户列表失败: {e}")
        return []


def add_user_to_db(username, password):
    """添加用户到数据库"""
    try:
        # 生成盐和密码哈希
        salt = str(uuid.uuid4())[:8]
        password_hash = hashlib.sha256((password + salt).encode()).hexdigest()

        db = get_db_connection()
        cursor = db.cursor()
        cursor.execute(
            "INSERT INTO users (username, password_hash, salt) VALUES (%s, %s, %s)",
            (username, password_hash, salt)
        )
        db.commit()
        db.close()
        return True, None
    except Exception as e:
        logger.error(f"添加用户失败: {e}")
        return False, str(e)


def update_user_password(username, password):
    """更新用户密码"""
    try:
        # 生成新的盐和密码哈希
        salt = str(uuid.uuid4())[:8]
        password_hash = hashlib.sha256((password + salt).encode()).hexdigest()

        db = get_db_connection()
        cursor = db.cursor()
        cursor.execute(
            "UPDATE users SET password_hash = %s, salt = %s WHERE username = %s",
            (password_hash, salt, username)
        )
        db.commit()
        db.close()
        return True, None
    except Exception as e:
        logger.error(f"更新用户密码失败: {e}")
        return False, str(e)


def delete_user_from_db(username):
    """从数据库删除用户"""
    try:
        db = get_db_connection()
        cursor = db.cursor()
        cursor.execute("DELETE FROM users WHERE username = %s", (username,))
        db.commit()
        db.close()
        return True, None
    except Exception as e:
        logger.error(f"删除用户失败: {e}")
        return False, str(e)


# 修改 settings 路由
@app.route('/settings', methods=['GET', 'POST'])
def settings():
    """系统设置页面"""
    if request.method == 'POST':
        # 更新API前缀
        new_prefix = request.form.get('api_prefix', Config.API_PREFIX).strip()
        if new_prefix:
            Config.API_PREFIX = new_prefix

        # 更新管理员密码
        admin_password = request.form.get('admin_password', '')
        if admin_password:
            success, error = update_user_password('admin', admin_password)
            if not success:
                return render_template('settings.html',
                                       api_prefix=Config.API_PREFIX,
                                       users=get_all_users(),
                                       error=f"更新管理员密码失败: {error}")

        # 添加新用户
        new_user = request.form.get('new_user', '').strip()
        new_password = request.form.get('new_password', '').strip()
        if new_user and new_password:
            success, error = add_user_to_db(new_user, new_password)
            if not success:
                return render_template('settings.html',
                                       api_prefix=Config.API_PREFIX,
                                       users=get_all_users(),
                                       error=f"添加用户失败: {error}")

        # 删除用户
        user_to_delete = request.form.get('user_to_delete', '').strip()
        if user_to_delete and user_to_delete != 'admin':
            success, error = delete_user_from_db(user_to_delete)
            if not success:
                return render_template('settings.html',
                                       api_prefix=Config.API_PREFIX,
                                       users=get_all_users(),
                                       error=f"删除用户失败: {error}")

        return redirect(url_for('settings'))

    return render_template('settings.html',
                           api_prefix=Config.API_PREFIX,
                           users=get_all_users())


# 在Main.py中添加以下路由

@app.route('/api/<api_id>/export')
def export_api(api_id):
    """导出API"""
    if api_id not in api_metadata:
        abort(404, description=f"API '{api_id}' not found")

    # 获取API元数据和脚本内容
    api_info = api_metadata[api_id].copy()
    script_content, error = script_storage.load_script(api_id)

    if error:
        abort(500, description=f"Failed to load script: {error}")

    # 创建导出数据
    export_data = {
        'version': '1.0',
        'api_id': api_id,
        'metadata': api_info,
        'script': script_content,
        'export_date': time.strftime("%Y-%m-%d %H:%M:%S")
    }

    # 返回JSON文件下载
    response = jsonify(export_data)
    response.headers['Content-Disposition'] = f'attachment; filename={api_id}_export.json'
    return response


@app.route('/api/import', methods=['GET', 'POST'])
def import_api():
    """导入API"""
    if request.method == 'POST':
        if 'file' not in request.files:
            return render_template('import.html', error="No file selected")

        file = request.files['file']
        if file.filename == '':
            return render_template('import.html', error="No file selected")

        if file and file.filename.endswith('.json'):
            try:
                # 解析上传的JSON文件
                data = json.load(file.stream)

                # 验证文件格式
                if 'version' not in data or 'metadata' not in data or 'script' not in data:
                    return render_template('import.html', error="Invalid file format")

                # 获取或生成API ID
                api_id = data.get('api_id', str(uuid.uuid4())[:8])

                # 如果API已存在，添加后缀
                original_api_id = api_id
                counter = 1
                while api_id in api_metadata:
                    api_id = f"{original_api_id}_{counter}"
                    counter += 1

                # 更新元数据
                metadata = data['metadata']
                metadata['imported_at'] = time.strftime("%Y-%m-%d %H:%M:%S")
                if 'created_at' not in metadata:
                    metadata['created_at'] = metadata['imported_at']

                # 保存脚本
                script_content = data['script']
                success, error = script_storage.save_script(api_id, script_content)
                if not success:
                    return render_template('import.html', error=f"Failed to save script: {error}")

                # 保存元数据
                api_metadata[api_id] = metadata
                save_api_metadata()

                # 重定向到新导入的API详情页面
                return redirect(url_for('api_detail', api_id=api_id))

            except json.JSONDecodeError:
                return render_template('import.html', error="Invalid JSON file")
            except Exception as e:
                return render_template('import.html', error=f"Import failed: {str(e)}")

        return render_template('import.html', error="Invalid file type. Please upload a JSON file")

    return render_template('import.html')


@app.route('/api/batch_export', methods=['POST'])
def batch_export_apis():
    """批量导出选中的API"""
    try:
        selected_apis = request.json.get('apis', [])
        if not selected_apis:
            return jsonify({'error': 'No APIs selected'}), 400

        export_data = {
            'version': '1.0',
            'export_date': time.strftime("%Y-%m-%d %H:%M:%S"),
            'apis': []
        }

        for api_id in selected_apis:
            if api_id in api_metadata:
                # 获取API元数据和脚本内容
                api_info = api_metadata[api_id].copy()
                script_content, error = script_storage.load_script(api_id)

                if not error:
                    export_data['apis'].append({
                        'api_id': api_id,
                        'metadata': api_info,
                        'script': script_content
                    })

        # 返回JSON数据
        return jsonify(export_data)

    except Exception as e:
        return jsonify({'error': f'Export failed: {str(e)}'}), 500


@app.route('/api/batch_import', methods=['POST'])
def batch_import_apis():
    """批量导入API"""
    if 'file' not in request.files:
        return jsonify({'error': 'No file selected'}), 400

    file = request.files['file']
    if file.filename == '':
        return jsonify({'error': 'No file selected'}), 400

    if file and file.filename.endswith('.json'):
        try:
            # 解析上传的JSON文件
            data = json.load(file.stream)

            # 验证文件格式
            if 'version' not in data or 'apis' not in data:
                return jsonify({'error': 'Invalid file format'}), 400

            imported_apis = []
            skipped_apis = []

            for api_data in data['apis']:
                # 获取或生成API ID
                api_id = api_data.get('api_id', str(uuid.uuid4())[:8])

                # 如果API已存在，跳过或添加后缀
                original_api_id = api_id
                counter = 1
                while api_id in api_metadata:
                    if request.args.get('overwrite') == 'true':
                        break
                    api_id = f"{original_api_id}_{counter}"
                    counter += 1

                # 检查是否跳过已存在的API
                if api_id in api_metadata and request.args.get('overwrite') != 'true':
                    skipped_apis.append(api_id)
                    continue

                # 更新元数据
                metadata = api_data['metadata']
                metadata['imported_at'] = time.strftime("%Y-%m-%d %H:%M:%S")
                if 'created_at' not in metadata:
                    metadata['created_at'] = metadata['imported_at']

                # 保存脚本
                script_content = api_data['script']
                success, error = script_storage.save_script(api_id, script_content)
                if not success:
                    skipped_apis.append(api_id)
                    continue

                # 保存元数据
                api_metadata[api_id] = metadata
                imported_apis.append(api_id)

            # 保存所有元数据
            save_api_metadata()

            return jsonify({
                'message': f'Successfully imported {len(imported_apis)} APIs',
                'imported_apis': imported_apis,
                'skipped_apis': skipped_apis
            })

        except json.JSONDecodeError:
            return jsonify({'error': 'Invalid JSON file'}), 400
        except Exception as e:
            return jsonify({'error': f'Import failed: {str(e)}'}), 500

    return jsonify({'error': 'Invalid file type. Please upload a JSON file'}), 400


# 在main.py中添加以下路由
@app.route('/package_management')
def package_management():
    """包管理页面"""
    if 'user' not in session:
        return redirect(url_for('login'))
    return render_template('package_management.html')



def execute_pip_install(task_id, package_input, install_options=None):
    """在后台线程中执行pip安装"""
    try:
        # 构建pip命令
        if package_input.startswith('pip install'):
            command_parts = package_input.split()
            if '--target' not in command_parts and '-t' not in command_parts:
                install_index = command_parts.index('install') + 1
                command_parts.insert(install_index, '--target')
                command_parts.insert(install_index + 1, PERSISTENT_PACKAGE_DIR)
            command = command_parts
        else:
            command = ['pip', 'install', '--target', PERSISTENT_PACKAGE_DIR, package_input]

        # 添加包源配置
        if install_options and install_options.get('source'):
            source = install_options['source']
            # 找到install命令的位置
            install_index = command.index('install') + 1
            # 插入源参数
            command.insert(install_index, '-i')
            command.insert(install_index + 1, source)
            # 添加信任主机参数（避免SSL证书问题）
            command.insert(install_index + 2, '--trusted-host')
            # 从URL中提取主机名
            from urllib.parse import urlparse
            parsed_url = urlparse(source)
            hostname = parsed_url.hostname
            command.insert(install_index + 3, hostname if hostname else source.split('/')[2])

        # 添加其他安装选项
        if install_options:
            if install_options.get('no_deps'):
                command.append('--no-deps')
            if install_options.get('no_cache_dir'):
                command.append('--no-cache-dir')

        print(f"DEBUG: Executing pip command: {' '.join(command)}")

        # 执行pip命令
        result = subprocess.run(
            [sys.executable, '-m'] + command,
            capture_output=True,
            text=True,
            encoding='utf-8',
            errors='ignore',  # 忽略编码错误
            timeout=3000,
            env={**os.environ, 'PYTHONIOENCODING': 'utf-8'}  # 设置环境变量确保UTF-8输出
        )

        if result.returncode == 0:
            with tasks_lock:
                installation_tasks[task_id].update({
                    'status': 'completed',
                    'success': True,
                    'output': result.stdout,
                    'error': result.stderr,
                    'end_time': time.time()
                })
        else:
            with tasks_lock:
                installation_tasks[task_id].update({
                    'status': 'completed',
                    'success': False,
                    'output': result.stdout,
                    'error': result.stderr,
                    'end_time': time.time()
                })

    except subprocess.TimeoutExpired:
        with tasks_lock:
            installation_tasks[task_id].update({
                'status': 'completed',
                'success': False,
                'error': 'Installation timed out after 300 seconds',
                'end_time': time.time()
            })
    except Exception as e:
        with tasks_lock:
            installation_tasks[task_id].update({
                'status': 'completed',
                'success': False,
                'error': f'Installation failed: {str(e)}',
                'end_time': time.time()
            })


def execute_pip_uninstall(task_id, package_name):
    """在后台线程中执行pip卸载"""
    try:
        # 首先尝试使用pip卸载
        result = subprocess.run(
            [sys.executable, '-m', 'pip', 'uninstall', '-y', package_name],
            capture_output=True,
            text=True,
            encoding='utf-8',
            errors='ignore',  # 忽略编码错误
            timeout=300,
            env={**os.environ, 'PYTHONIOENCODING': 'utf-8'}  # 设置环境变量确保UTF-8输出
        )

        # 无论pip卸载是否成功，都尝试手动删除包文件
        removed_items = []
        if os.path.exists(PERSISTENT_PACKAGE_DIR):
            items = os.listdir(PERSISTENT_PACKAGE_DIR)

            # 查找与包名相关的所有文件和目录
            for item in items:
                item_normalized = item.replace('_', '-')
                package_name_normalized = package_name.replace('_', '-')

                # 检查是否匹配包目录或元数据文件
                if (item == package_name or
                        item_normalized == package_name_normalized or
                        item.startswith(package_name + '-') or
                        item_normalized.startswith(package_name_normalized + '-')):

                    item_path = os.path.join(PERSISTENT_PACKAGE_DIR, item)
                    try:
                        if os.path.isdir(item_path):
                            shutil.rmtree(item_path)
                        else:
                            os.remove(item_path)
                        removed_items.append(item)
                    except Exception as e:
                        print(f"Error removing {item_path}: {e}")

        # 清除该包的模块缓存
        cleared_modules = clear_package_cache(package_name)

        # 如果手动删除了文件，则认为卸载成功
        if removed_items:
            with tasks_lock:
                uninstallation_tasks[task_id].update({
                    'status': 'completed',
                    'success': True,
                    'output': f"Manually removed: {', '.join(removed_items)}. Cleared {cleared_modules} modules from cache.",
                    'error': result.stderr if result.returncode != 0 else "",
                    'end_time': time.time()
                })
        elif result.returncode == 0:
            with tasks_lock:
                uninstallation_tasks[task_id].update({
                    'status': 'completed',
                    'success': True,
                    'output': f"{result.stdout}. Cleared {cleared_modules} modules from cache.",
                    'error': result.stderr,
                    'end_time': time.time()
                })
        else:
            with tasks_lock:
                uninstallation_tasks[task_id].update({
                    'status': 'completed',
                    'success': False,
                    'output': result.stdout,
                    'error': result.stderr,
                    'end_time': time.time()
                })

    except subprocess.TimeoutExpired:
        with tasks_lock:
            uninstallation_tasks[task_id].update({
                'status': 'completed',
                'success': False,
                'error': 'Uninstallation timed out',
                'end_time': time.time()
            })
    except Exception as e:
        with tasks_lock:
            uninstallation_tasks[task_id].update({
                'status': 'completed',
                'success': False,
                'error': f'Uninstallation failed: {str(e)}',
                'end_time': time.time()
            })


#  install_package 路由，安装包：
@app.route('/api/install_package', methods=['POST'])
def install_package():
    """安装Python包到持久化目录 - 异步版本"""
    data = request.get_json()
    if not data or 'package' not in data:
        return jsonify({'error': 'Package name or command required'}), 400

    package_input = data['package'].strip()
    install_options = data.get('options', {})

    # 安全检查
    if not re.match(r'^[a-zA-Z0-9\.\_\-\=\<\>\s]+$', package_input):
        return jsonify({'error': 'Invalid package name or command'}), 400

    # 验证包源URL（如果提供了）
    if install_options.get('source'):
        source = install_options['source']
        if not re.match(r'^https?://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,}', source):
            return jsonify({'error': 'Invalid package source URL'}), 400

    # 生成任务ID
    task_id = str(uuid.uuid4())
    with tasks_lock:
        installation_tasks[task_id] = {
            'status': 'running',
            'package': package_input,
            'options': install_options,
            'start_time': time.time(),
            'end_time': None,
            'success': None,
            'output': '',
            'error': ''
        }

    # 在后台线程中执行安装
    thread = threading.Thread(
        target=execute_pip_install,
        args=(task_id, package_input, install_options)
    )
    thread.daemon = True
    thread.start()

    return jsonify({
        'task_id': task_id,
        'status': 'started',
        'message': f'Installation of {package_input} started'
    })


@app.route('/api/installed_packages')
def get_installed_packages():
    """获取已安装的包列表"""
    try:
        # 获取用户安装的包（在持久化目录中的包）
        user_packages = []

        # 检查持久化目录中的包
        if os.path.exists(PERSISTENT_PACKAGE_DIR):
            # 获取所有包目录和元数据文件
            items = os.listdir(PERSISTENT_PACKAGE_DIR)

            # 找出所有包目录（排除元数据文件和特殊目录）
            package_dirs = []
            metadata_files = []

            for item in items:
                item_path = os.path.join(PERSISTENT_PACKAGE_DIR, item)
                if os.path.isdir(item_path):
                    if not (item.endswith('.dist-info') or
                            item.endswith('.egg-info') or
                            item == '__pycache__'):
                        package_dirs.append(item)
                elif (item.endswith('.dist-info') or
                      item.endswith('.egg-info')):
                    metadata_files.append(item)

            # 为每个包目录查找对应的元数据
            for package_dir in package_dirs:
                # 尝试找到对应的元数据文件
                metadata_file = None
                package_name_normalized = package_dir.replace('_', '-')

                for mfile in metadata_files:
                    if mfile.startswith(package_name_normalized + '-'):
                        metadata_file = mfile
                        break

                # 提取版本信息
                version = "unknown"
                if metadata_file:
                    # 从元数据文件名中提取版本
                    version_match = re.search(r'-(.+?)\.(dist-info|egg-info)', metadata_file)
                    if version_match:
                        version = version_match.group(1)

                user_packages.append({
                    'name': package_dir,
                    'version': version
                })

        # 按名称排序
        user_packages.sort(key=lambda x: x['name'].lower())

        return jsonify({'packages': user_packages})
    except Exception as e:
        return jsonify({'error': f'Failed to get packages: {str(e)}'}), 500


@app.route('/api/uninstall_package', methods=['POST'])
def uninstall_package():
    """卸载Python包 - 异步版本"""
    data = request.get_json()
    if not data or 'package' not in data:
        return jsonify({'error': 'Package name required'}), 400

    package_name = data['package'].strip()

    # 安全检查
    if not re.match(r'^[a-zA-Z0-9\.\_\-]+$', package_name):
        return jsonify({'error': 'Invalid package name'}), 400

    # 生成任务ID
    task_id = str(uuid.uuid4())
    with tasks_lock:
        uninstallation_tasks[task_id] = {
            'status': 'running',
            'package': package_name,
            'start_time': time.time(),
            'end_time': None,
            'success': None,
            'output': '',
            'error': ''
        }

    # 在后台线程中执行卸载
    thread = threading.Thread(
        target=execute_pip_uninstall,
        args=(task_id, package_name)
    )
    thread.daemon = True
    thread.start()

    return jsonify({
        'task_id': task_id,
        'status': 'started',
        'message': f'Uninstallation of {package_name} started'
    })


@app.route('/api/installation_status/<task_id>')
def installation_status(task_id):
    """检查安装任务状态"""
    with tasks_lock:
        if task_id not in installation_tasks:
            return jsonify({'error': 'Task not found'}), 404

        task = installation_tasks[task_id].copy()

    return jsonify(task)


@app.route('/api/uninstallation_status/<task_id>')
def uninstallation_status(task_id):
    """检查卸载任务状态"""
    with tasks_lock:
        if task_id not in uninstallation_tasks:
            return jsonify({'error': 'Task not found'}), 404

        task = uninstallation_tasks[task_id].copy()

    return jsonify(task)


@app.route('/admin/fix_consistency')
def admin_fix_consistency():
    """管理员工具：修复数据一致性"""
    if 'user' not in session:
        return redirect(url_for('login'))

    success1, message1 = check_data_consistency()
    success2, message2 = cleanup_orphaned_scripts()

    if success1 and success2:
        return jsonify({
            'status': 'success',
            'message': f"Data consistency fixed: {message1}. {message2}"
        })
    else:
        return jsonify({
            'status': 'error',
            'message': f"Fix failed: {message1}. {message2}"
        }), 500

@app.context_processor
def inject_global_variables():
    return {
        'apis': api_metadata,
        'api_prefix': Config.API_PREFIX,
        'api_keys_count': len(get_all_users())
    }


# 初始化 - 加载已有的API元数据
logger.info("Starting application initialization...")
load_api_metadata()

# 启动时清理孤儿数据
logger.info("Cleaning up orphaned data on startup...")
cleanup_orphaned_scripts()

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5001, debug=True,use_reloader=False)
    # app.run(host='0.0.0.0', port=5000)

    # import uvicorn
    #
    # uvicorn.run(app, host="0.0.0.0", port=5001)
